package com.zytlifeservice.controller.pay;

import com.alipay.demo.trade.config.Configs;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.qianmi.open.api.ApiException;
import com.zytlifeservice.config.WxConfig;
import com.zytlifeservice.domain.Result;
import com.zytlifeservice.domain.pay.*;
import com.zytlifeservice.exception.UserException;
import com.zytlifeservice.repository.pay.*;
import com.zytlifeservice.service.pay.*;
import com.zytlifeservice.util.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by MJS on 2017/5/26.
 */

@RequestMapping(value = "/callback")
@Controller
public class CallBackReceiveController {

    private static final Logger logger = LoggerFactory.getLogger(CallBackReceiveController.class);

    @Autowired
    AlipayService alipayService;

    @Autowired
    WxPayService wxPayService;

    @Autowired
    WxPayOrderRepository wxPayOrderRepository;

    @Autowired
    AlipayOrderRepository alipayOrderRepository;

    @Autowired
    MobileRechargeService mobileRechargeService;

    @Autowired
    BroadBandAndPhoneService broadBandAndPhoneService;

    @Autowired
    WaterCoalService waterCoalService;

    @Autowired
    MobileRechargeOrderRepository mobileRechargeOrderRepository;

    @Autowired
    BroadBandAndPhoneRepository broadBandAndPhoneRepository;

    @Autowired
    WaterCoalOrderRepository waterCoalOrderRepository;


    @Autowired
    FlowRechargeOrderRepository flowRechargeOrderRepository;

    @Autowired
    WiredTvRechargeOrderService wiredTvRechargeOrderService;

    @Autowired
    FlowRechargeOrderService flowRechargeOrderService;

    @Autowired
    WiredTvRechargeOrderRepository wiredTvRechargeOrderRepository;

    @Autowired
    TrainRechargeOrderRepository trainRechargeOrderRepository;

    @Autowired
    AirplaneRechargeOrderRepository airplaneRechargeOrderRepository;

    @Autowired
    AirplaneService airplaneService;

    @Autowired
    TrainService trainService;

    @Autowired
    PublicService publicService;
    @Autowired
    WxConfig wxConfig;

    @RequestMapping(value = "/alipay/receive")
    @ResponseBody
    public String alipayReceive(HttpServletRequest request, HttpServletResponse response) throws ApiException {
        Map<String, String> requestParams = getRequestParams(request);
        String outTradeNo = requestParams.get("out_trade_no");
        AlipayOrder alipayOrder = alipayOrderRepository.findByOutTradeNo(outTradeNo);
        parseResponse(requestParams, alipayOrder);
        //要加一个等待的状态，如果是等待的状态，则什么都不做。
        String result = alipayVerify(requestParams);
        if ("success".equals(result)) {
            alipayOrder.setOrderStatus(AlipayOrder.ORDER_SUCCESS);
            alipayOrderRepository.save(alipayOrder);
            switch (alipayOrder.getType()) {
                case AlipayOrder.TYPE_MOBILE_RECHARGE:
                    mobileRechargeService.payPhoneChargeOrder(outTradeNo);
                    break;

                case AlipayOrder.TYPE_MOBILE_FLOW:
                    flowRechargeOrderService.payFlowChargeOrder(outTradeNo);
                    break;

                case AlipayOrder.TYPE_CATV:
                    wiredTvRechargeOrderService.payWiredTvChargeOrder(outTradeNo);
                    break;

                case AlipayOrder.TYPE_GHKD_RECHARGE:
                    broadBandAndPhoneService.pay(outTradeNo);
                    break;

                case AlipayOrder.TYPE_ELECTRIC:
                case AlipayOrder.TYPE_COAL:
                case AlipayOrder.TYPE_WATER:
                    waterCoalService.pay(outTradeNo);
                    break;

                case AlipayOrder.TYPE_TRAIN:
                    trainService.pay(outTradeNo);
                    break;

                case AlipayOrder.TYPE_AIRPLANE:
                    airplaneService.pay(outTradeNo);
                    break;

                default:
                    break;
            }
        } else if ("fail".equals(result)) {
            //失败，直接更新订单状态了。  验证失败，人工介入。
            alipayOrder.setOrderStatus(AlipayOrder.ORDER_EXCEPTION);
            alipayOrderRepository.save(alipayOrder);
        } else if ("wait".equals(result)) {
            alipayOrder.setOrderStatus(AlipayOrder.ORDER_WAIT);
            alipayOrderRepository.save(alipayOrder);
            return "fail";
        }
        return "success";
    }

    private void parseResponse(Map<String, String> requestParams, AlipayOrder alipayOrder) {
        alipayOrder.setTrade_no(requestParams.get("trade_no"));
        alipayOrder.setGmt_create(requestParams.get("gmt_create"));
        alipayOrder.setGmt_payment(requestParams.get("gmt_payment"));
    }

    private Map getRequestParams(HttpServletRequest request) {
        Map requestParams = request.getParameterMap();
        Map params = new HashMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        logger.error("订单orderCode：{}所对应的支付宝通知交易码为{}返回参数列表：{}", new Object[]{params.get("out_trade_no"), params.get("trade_no"), params.toString()});
        return params;
    }

    private String alipayVerify(Map<String, String> params) {
        String result = "fail";
//        try {
        logger.error("publicKey={}", Configs.getPublicKey());
        logger.error("charset={}", params.get("charset"));
        logger.error("sign_type={}", params.get("sign_type"));
//            if (AlipaySignature.rsaCheckV1(params, Configs.getPublicKey(), params.get("charset"), params.get("sign_type"))) {
        String out_trade_no = params.get("out_trade_no");
        String total_amount = params.get("total_amount");
        String seller_email = params.get("seller_email");
        String trade_status = params.get("trade_status");
        String notify_type = params.get("notify_type");
        AlipayOrder order = alipayOrderRepository.findByOutTradeNo(out_trade_no);

        logger.error("alipayOrder={}", order);
        //这里应该转为float在做比较。否者，末尾多0的话也通不过验证。
        if (comparePriceStr(order.getTotalAmount(), total_amount)) {
            if ("209455624@qq.com".equals(seller_email)) {
                if ("trade_status_sync".equals(notify_type)) {
                    if ("WAIT_BUYER_PAY".equals(trade_status)) {
                        result = "wait";
                    } else if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
                        logger.error("支付宝验签通过，执行千米消费流程");
                        result = "success";
                    } else {
                        logger.error("trade_status no");
                    }
                } else {
                    logger.error("nofity_type no");
                }
            } else {
                logger.error("email no");
            }
        } else {
            logger.error("total_amount no");
        }
//        }
//            else {
//                logger.error("验签失败");
//            }
//        }
//    catch(
//     AlipayApiException e)
//
//    {
//        e.printStackTrace();
//        logger.error("发生异常:" + e.getErrMsg());
//    }
        logger.error("验证失败");
        return result;
    }

    private boolean comparePriceStr(String priceOne, String priceTwo) {
        try {
            float price_one = Float.parseFloat(priceOne);
            float price_two = Float.parseFloat(priceTwo);
            return price_one == price_two;
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return false;
    }


    @RequestMapping(value = "/wxpay/receive")
    @ResponseBody
    public String wxPayReceive(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.error("request = {}", request);
        String notifyData = getNotifyData(request);
        WXPay wxpay = new WXPay(wxConfig);
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);
        String outTradeNo = notifyMap.get("out_trade_no");
        WxPayOrder order = wxPayOrderRepository.findByOutTradeNo(outTradeNo);
        logger.error("wxOrder={}", order);
        parseWxResponse(order, notifyMap);
        if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
            // 签名正确
            // 进行处理。
            // 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功
            logger.error("微信支付验签成功，执行千米消费流程");
            order.setOrderStatus(WxPayOrder.ORDER_SUCCESS);
            switch (order.getType()) {
                case WxPayOrder.TYPE_MOBILE_RECHARGE:
                    mobileRechargeService.payPhoneChargeOrder(outTradeNo);
                    break;

                case WxPayOrder.TYPE_MOBILE_FLOW:
                    flowRechargeOrderService.payFlowChargeOrder(outTradeNo);
                    break;

                case WxPayOrder.TYPE_CATV:
                    wiredTvRechargeOrderService.payWiredTvChargeOrder(outTradeNo);
                    break;

                case WxPayOrder.TYPE_GHKD_RECHARGE:
                    broadBandAndPhoneService.pay(outTradeNo);
                    break;

                case WxPayOrder.TYPE_ELECTRIC:
                case WxPayOrder.TYPE_COAL:
                case WxPayOrder.TYPE_WATER:
                    waterCoalService.pay(outTradeNo);
                    break;


                case WxPayOrder.TYPE_TRAIN:
                    trainService.pay(outTradeNo);
                    break;

                case WxPayOrder.TYPE_AIRPLANE:
                    airplaneService.pay(outTradeNo);
                    break;

                default:
                    break;
            }
            wxPayOrderRepository.save(order);
        } else {
            // 签名错误，如果数据里没有sign字段，也认为是签名错误
            order.setOrderStatus(WxPayOrder.ORDER_EXCEPTION);
            wxPayOrderRepository.save(order);
        }
        return "SUCCESS";

    }

    private void parseWxResponse(WxPayOrder order, Map<String, String> notifyMap) {
        order.setTradeNo(notifyMap.get("transaction_id"));
        String time = notifyMap.get("time_end");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        try {
            Date parse = sdf.parse(time);
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            order.setTime_end(sdf.format(parse));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    private String getNotifyData(HttpServletRequest request) throws IOException {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();
        String result = new String(outSteam.toByteArray(), "utf-8");
        System.out.println("callBack_xml>>>" + result);
        logger.error("微信 call back result = " + result);
        return result;
    }


    @PostMapping(value = "/queryPayResult")
    @ResponseBody
    public Result queryPayResult(String outTradeNo, long userId) {
        AlipayOrder alipayOrder = alipayOrderRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
        String result = "wait";
        if (alipayOrder != null) {
            int orderStatus = alipayOrder.getOrderStatus();
            if (orderStatus == AlipayOrder.ORDER_SUCCESS) {
                result = "success";
            } else if (orderStatus == AlipayOrder.ORDER_FAIL) {
                result = "fail";
            } else if (orderStatus == AlipayOrder.ORDER_EXCEPTION) {
                result = "fail";
            }
        } else {
            WxPayOrder wxPayOrder = wxPayOrderRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
            if (wxPayOrder != null) {
                int orderStatus = wxPayOrder.getOrderStatus();
                if (orderStatus == WxPayOrder.ORDER_SUCCESS) {
                    result = "success";
                } else if (orderStatus == WxPayOrder.ORDER_FAIL) {
                    result = "fail";
                } else if (orderStatus == WxPayOrder.ORDER_EXCEPTION) {
                    result = "fail";
                }
            } else {
                throw new UserException("查询失败", 303);
            }
        }
        return ResultUtil.success(result, "查询成功");
    }

    @PostMapping(value = "/queryByOutTradeNo")
    @ResponseBody
    public Result queryCallBckByOutTradeNo(@RequestParam("outTradeNo") String outTradeNo,
                                           @RequestParam("type") int type,
                                           @RequestParam("userId") Long userId) {
        switch (type) {
            case AlipayOrder.TYPE_MOBILE_RECHARGE:
                MobileRechargeOrder order = mobileRechargeOrderRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
                if (order == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(order.getPayResult(), "查询成功");

            case AlipayOrder.TYPE_GHKD_RECHARGE:
                BroadBandAndPhoneDomain broadOrder = broadBandAndPhoneRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
                if (broadOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(broadOrder.getPayResult(), "查询成功");


            case AlipayOrder.TYPE_WATER:
                WaterCoalOrder waterOrder = waterCoalOrderRepository.findByOutTradeNoAndUserIdAndType(outTradeNo, userId, WaterCoalOrder.TYPE_WATER);
                if (waterOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(waterOrder.getPayResult(), "查询成功");

            case AlipayOrder.TYPE_ELECTRIC:
                WaterCoalOrder electricOrder = waterCoalOrderRepository.findByOutTradeNoAndUserIdAndType(outTradeNo, userId, WaterCoalOrder.TYPE_ELECTRIC);
                if (electricOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(electricOrder.getPayResult(), "查询成功");

            case AlipayOrder.TYPE_COAL:
                WaterCoalOrder coalOrder = waterCoalOrderRepository.findByOutTradeNoAndUserIdAndType(outTradeNo, userId, WaterCoalOrder.TYPE_COAL);
                if (coalOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(coalOrder.getPayResult(), "查询成功");

            case AlipayOrder.TYPE_CATV:
                WiredTvRechargeOrder wiredTvRechargeOrder = wiredTvRechargeOrderRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
                if (wiredTvRechargeOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(wiredTvRechargeOrder.getPayResult(), "查询成功");
            case AlipayOrder.TYPE_MOBILE_FLOW:
                FlowRechargeOrder flowRechargeOrder = flowRechargeOrderRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
                if (flowRechargeOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(flowRechargeOrder.getPayResult(), "查询成功");

            case AlipayOrder.TYPE_TRAIN:
                TrianRechargeOrder trainOrder = trainRechargeOrderRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
                if (trainOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(trainOrder.getPayResult(), "查询成功");

            case AlipayOrder.TYPE_AIRPLANE:
                AirplaneRechargeOrder airOrder = airplaneRechargeOrderRepository.findByOutTradeNoAndUserId(outTradeNo, userId);
                if (airOrder == null) {
                    throw new UserException("查询失败", 203);
                }
                return ResultUtil.success(airOrder.getPayResult(), "查询成功");
        }
        return ResultUtil.error(203, "查询失败");
    }


    @PostMapping(value = "/queryBills")
    @ResponseBody
    public Result queryBills(@RequestParam("userId") Long userId,
                             @RequestParam("type") int type) {
        List<Bill> bills = new ArrayList<>();
        logger.error("查询type={}", type);
        switch (type) {
            case AlipayOrder.TYPE_MOBILE_RECHARGE:
                //这里获取之后，截取字段处理。
                for (MobileRechargeOrder order : mobileRechargeOrderRepository.findAllByUserId(userId)) {
                    bills.add(Bill.getBill(order, "话费充值"));
                }
                break;
            case AlipayOrder.TYPE_MOBILE_FLOW:
                //这里获取之后，截取字段处理。
                for (FlowRechargeOrder order : flowRechargeOrderRepository.findAllByUserId(userId)) {
                    bills.add(Bill.getBill(order, "流量充值"));
                }
                break;

            case AlipayOrder.TYPE_CATV:
                //这里获取之后，截取字段处理。
                for (WiredTvRechargeOrder order : wiredTvRechargeOrderRepository.findAllByUserId(userId)) {
                    bills.add(Bill.getBill(order, "有线电视缴费"));
                }
                break;

            case AlipayOrder.TYPE_GHKD_RECHARGE:
                for (BroadBandAndPhoneDomain bandAndPhoneDomain : broadBandAndPhoneRepository.findAllByUserId(userId)) {
                    bills.add(Bill.getBill(bandAndPhoneDomain, "宽带缴费"));
                }
                break;

            case AlipayOrder.TYPE_WATER:
                for (WaterCoalOrder waterOrder : waterCoalOrderRepository.findAllByUserIdAndType(userId, WaterCoalOrder.TYPE_WATER)) {
                    bills.add(Bill.getBill(waterOrder, "水费缴费"));
                }
                break;

            case AlipayOrder.TYPE_ELECTRIC:
                for (WaterCoalOrder electricOrder : waterCoalOrderRepository.findAllByUserIdAndType(userId, WaterCoalOrder.TYPE_ELECTRIC)) {
                    bills.add(Bill.getBill(electricOrder, "电费缴费"));
                }
                break;

            case AlipayOrder.TYPE_COAL:
                for (WaterCoalOrder coalOrder : waterCoalOrderRepository.findAllByUserIdAndType(userId, WaterCoalOrder.TYPE_COAL)) {
                    bills.add(Bill.getBill(coalOrder, "燃气费缴费"));
                }
                break;

            default:
                return ResultUtil.error(202, "类型错误");
        }
        //筛选交易状态。
        for (Bill bill : new ArrayList<>(bills)) {
            if (bill.getStatus().equals(BaseQmOrder.STATUS_INIT)) {
                bills.remove(bill);
            }
        }
        return ResultUtil.success(bills, "查询成功");
    }

    @RequestMapping(value = "/bmCallBack")
    @ResponseBody
    public String BMCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, String> requestParams = getRequestParams(request);
        logger.error("斑马 回调参数={}", requestParams);
        BaseQmOrder baseQmOrder = verifyBmCallBackParams(requestParams);
        if (baseQmOrder != null) {
            String outTradeNo = requestParams.get("outer_tid");
            String recharge_state = requestParams.get("recharge_state");
            if ("9".equals(recharge_state)) {
                //这里更新订单最终的状态。
                baseQmOrder.setPayResult(BaseQmOrder.STATUS_FAIL);
                baseQmOrder.setFailReason("千米订单失败");
                publicService.refundPay(outTradeNo, "");
            } else if ("1".equals(recharge_state)) {  //交易成功
                baseQmOrder.setPayResult(BaseQmOrder.STATUS_SUCCESS);
                publicService.addScore(baseQmOrder);
            }
            updateQmOrderStatus(baseQmOrder);
            return "success";
        } else {
            //直接走支付的流程。
            return "fail";
        }
    }

    private void updateQmOrderStatus(BaseQmOrder baseQmOrder) {
        if (baseQmOrder instanceof MobileRechargeOrder) {
            mobileRechargeOrderRepository.save((MobileRechargeOrder) baseQmOrder);
        } else if (baseQmOrder instanceof FlowRechargeOrder) {
            flowRechargeOrderRepository.save((FlowRechargeOrder) baseQmOrder);
        } else if (baseQmOrder instanceof BroadBandAndPhoneDomain) {
            broadBandAndPhoneRepository.save((BroadBandAndPhoneDomain) baseQmOrder);
        } else if (baseQmOrder instanceof WiredTvRechargeOrder) {
            wiredTvRechargeOrderRepository.save((WiredTvRechargeOrder) baseQmOrder);
        } else if (baseQmOrder instanceof WaterCoalOrder) {
            waterCoalOrderRepository.save((WaterCoalOrder) baseQmOrder);
        }
    }

    private BaseQmOrder verifyBmCallBackParams(Map<String, String> requestParams) {
        String outer_tid = requestParams.get("outer_tid");
        String user_id = requestParams.get("user_id");
        String sign = requestParams.get("sign");
        String tid = requestParams.get("tid");
        //通过订单号，去查找是否在本地的数据库有记录，有记录的话，再次对比直销商的id,内部订单号
        BaseQmOrder order = findBeanByOutTradeNo(outer_tid);
        logger.error("baseQmOrder= {}", order);
        if (order != null) {
            String userCode = order.getUserCode();
            String billId = order.getBillId();
            if (user_id.equals(userCode) && tid.equals(billId)) {
                return order;
            }
        }
        return null;
    }

    private BaseQmOrder findBeanByOutTradeNo(String outer_tid) {
        List<BaseQmOrder> list = new ArrayList<>();
        MobileRechargeOrder mobileRechargeOrder = mobileRechargeOrderRepository.findByOutTradeNo(outer_tid);
        BroadBandAndPhoneDomain broadBandAndPhoneDomain = broadBandAndPhoneRepository.findByOutTradeNo(outer_tid);
        WaterCoalOrder waterCoalOrder = waterCoalOrderRepository.findByOutTradeNo(outer_tid);
        WiredTvRechargeOrder wiredTvRechargeOrder = wiredTvRechargeOrderRepository.findByOutTradeNo(outer_tid);
        FlowRechargeOrder flowRechargeOrder = flowRechargeOrderRepository.findByOutTradeNo(outer_tid);

        list.add(mobileRechargeOrder);
        list.add(broadBandAndPhoneDomain);
        list.add(waterCoalOrder);
        list.add(wiredTvRechargeOrder);
        list.add(flowRechargeOrder);

        for (BaseQmOrder order : list) {
            if (order != null) {
                return order;
            }
        }
        return null;
    }
}
